package com.nio.c5_网络编程.selector.readServer;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * @version No one is coming, unless you change yourself!!!
 * @author： pang-yun
 * @date： 2021-05-31 20:59
 */

//解决 上一种非阻塞 一直占用CPU的问题，有事件发生时采用非阻塞模式，无事件发生时采用阻塞模式

    /*- 1. 打开selector  serverSocketChannel  并将ssc注册进入selector  得到 key  key决定监听什么类型的事件
                      selector 中
    -   2.  从selector 中拿到 key 集合

    * */


@Slf4j
public class SelectorServer {
    public static void main(String[] args) throws IOException {
        // 1.创建selector  可以用来管理多个channel   相当于一个管理中心
        Selector selector = Selector.open();

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);

        //2.建立selector 和channel 的联系（注册中心）
        //SelectionKey 就是将来事件发生以后，通过它可以知道事件和哪个？channel的事件！！   0 表示不关注 任何事件
        SelectionKey selectionKey = serverSocketChannel.register(selector, 0, null);

        //四种事件中，key只关注accept事件  从而确定阻塞 非阻塞 ，将其设置为 只关注accept模式  有连接请求时触发
        selectionKey.interestOps(SelectionKey.OP_ACCEPT);
        log.debug("register key :{}",selectionKey);

                serverSocketChannel.bind(new InetSocketAddress(9999));

        while (true) {
            //3. select方法， 没有事件时，线程阻塞， 有事件，线程才回复运行         // 如果事件不处理 就是一直不阻塞  注意使用 cancel 来取消
            // 不能置之不理
            selector.select();
            //4. 开始处理事件， selectKeys     内部包含了所有发生的事件
            //selector.selectedKeys();

            //以后我们会需要在 集合中删除一些事件  所以需要 使用迭代器
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                log.debug("selection key: {}",key);
                //得到selectionKey后，我们可以通过它知道 Channel ,再让channel建立连接
              /*  ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                SocketChannel socketChannel = channel.accept();
                log.debug("{}",socketChannel);*/
                //得到事件之后不想处理  采用cancel方法
                key.cancel();
            }
        }

    }
}
